#include <sys_config.h>
#include <osal/osal.h>
#include <basic_types.h>

#include <api/libc/alloc.h>
#include <api/libc/printf.h>
#include <api/libc/string.h>

#include <hld/hld_dev.h>
#include <hld/dmx/dmx_dev.h>
#include <hld/dmx/dmx.h>

#include <api/libtsi/si_types.h>
//#include <api/libtsi/si_table.h>

#include <api/libttx/lib_ttx.h>
#include <hld/hld_dev.h>
#include <hld/vbi/vbi.h>
#include <hld/vbi/vbi_dev.h>

#ifdef LIB_TSI3_FULL
#include <api/libtsi/si_section.h>
#include <api/libsi/desc_loop_parser.h>
#include <api/libsi/sie_monitor.h>
#endif

#ifndef SEE_CPU
#define LIBTTX_PRINTF PRINTF
//#define LIBTTX_PRINTF libc_printf

OSAL_ID TTX_SEM_ID = INVALID_ID;
static BOOL g_ttx_enable = FALSE;
static BOOL g_ttx_channel_enable = FALSE;
static BOOL g_ttx_pvr_enable = FALSE;

struct vbi_device *ttx_dev = NULL;
static UINT16 dmx_index = 0;

static struct t_ttx_lang g_init_page[TTX_SUBT_LANG_NUM];
static UINT8 g_init_page_num = 0;
static struct t_ttx_lang g_subt_page[TTX_SUBT_LANG_NUM];
static UINT8 g_subt_page_num = 0;

#ifdef PVR_DYNAMIC_PID_MONITOR_SUPPORT

static struct t_ttx_lang rec_monitor_id_g_init_page[2][2][TTX_SUBT_LANG_NUM];
static UINT8 rec_monitor_id_g_init_page_num[2][2];
static struct t_ttx_lang rec_monitor_id_g_subt_page[2][2][TTX_SUBT_LANG_NUM];
static UINT8 rec_monitor_id_g_subt_page_num[2][2];

#endif

static UINT8 g_current_init_page = 0xff;
static UINT8 g_current_subt_page = 0xff;
static UINT16 g_current_pid =0x1fff;

static BOOL g_init_page_enable = TRUE;
static UINT16 g_init_page_id = 100;
static UINT8 seperate_ttxsubtitle_mode = 0;

static UINT8* g_current_language;
    
static TTX_EVENT_CALLBACK ttx_event_callback = NULL;

static BOOL g_is_ttx_available = FALSE;

BOOL ttx_is_available()
{
	return g_is_ttx_available;
}
	
INT32 ttx_descriptor(UINT8 tag, INT32 desc_length, UINT8 *desc, void *param);

void set_seperate_ttxsubt_mode(UINT8 mode)
{
    seperate_ttxsubtitle_mode = mode;
    vbi_ioctl(ttx_dev,IO_VBI_WORK_MODE_SEPERATE_TTX_SUBT, (UINT32)mode);
}

void set_ttx_history_mode(BOOL mode)
{
    vbi_ioctl(ttx_dev,IO_VBI_WORK_MODE_HISTORY, (UINT32)mode);
}

INT32 TTXEng_Open(UINT8 subtitle,UINT16 page_num)
{
	osal_semaphore_capture(TTX_SEM_ID,OSAL_WAIT_FOREVER_TIME);
    vbi_ioctl(ttx_dev,IO_VBI_ENGINE_OPEN, (((subtitle&0xff)<<16)|(page_num&0xffff)));
	osal_semaphore_release(TTX_SEM_ID);
    //libc_printf("TTXEng_Open finish\n");
	return SUCCESS;

}

void  TTXEng_Close(void)
{
    //libc_printf("--TTXEng_Close--\n");
	osal_semaphore_capture(TTX_SEM_ID,OSAL_WAIT_FOREVER_TIME);
	vbi_ioctl(ttx_dev,IO_VBI_ENGINE_CLOSE, 0);
	osal_semaphore_release(TTX_SEM_ID);
}

void TTXEng_UpdPage(UINT16 page_id, UINT8 line_id)
{
	osal_semaphore_capture(TTX_SEM_ID,OSAL_WAIT_FOREVER_TIME);
    vbi_ioctl(ttx_dev,IO_VBI_ENGINE_UPDATE_PAGE, (((page_id&0xffff)<<8)|(line_id&0xff)));
	osal_semaphore_release(TTX_SEM_ID);
}

void  TTXEng_ShowOnOff(BOOL bOn)
{
	osal_semaphore_capture(TTX_SEM_ID,OSAL_WAIT_FOREVER_TIME);
    vbi_ioctl(ttx_dev,IO_VBI_ENGINE_SHOW_ON_OFF, bOn);
	osal_semaphore_release(TTX_SEM_ID);
}

void TTXEng_SendKey(TTX_KEYTYPE key)
{
	osal_semaphore_capture(TTX_SEM_ID,OSAL_WAIT_FOREVER_TIME);
    vbi_ioctl(ttx_dev,IO_VBI_ENGINE_SEND_KEY, (UINT32)key);
	osal_semaphore_release(TTX_SEM_ID);
}

void TTXEng_default_g0_set(UINT8 g0_set)
{
    if(ttx_dev == NULL)
    {
        if((ttx_dev = (struct vbi_device *)dev_get_by_type(NULL,HLD_DEV_TYPE_VBI))==NULL)
    	{
    		PRINTF("ttx_dev NOT exist!!\n");
    		ASSERT(0);
    	}
    }
	ttx_default_g0_set(ttx_dev,g0_set);
	vbi_ioctl(ttx_dev,IO_TTX_USER_DSG_FONT, (UINT32)g0_set);
}

#ifdef LIB_TSI3_FULL

static UINT8 prev_ttext[256];
struct desc_table ttx_desc_info[] = {
	{
		TELTEXT_DESCRIPTOR,
		0,
		(desc_parser_t)ttx_descriptor,
	},
};
INT32 ttx_callback(UINT8 *buff, INT32 len, UINT32 param)
{
	INT32 prog_info_length;
	INT32 es_info_length;
	INT32 i;
	UINT16 es_pid;
	
	struct pmt_section *pms = (struct pmt_section *)buff;
	struct pmt_stream_info *stream;
         g_is_ttx_available = FALSE;
	if(ttx_is_holded())
		return SUCCESS;
	
	prog_info_length = SI_MERGE_HL8(pms->program_info_length);
	
	for(i=sizeof(struct pmt_section)+prog_info_length-4; i<len-4; i+=es_info_length+sizeof(struct pmt_stream_info)) 
	{
		stream = (struct pmt_stream_info *)(buff+i);
		es_info_length = SI_MERGE_HL8(stream->es_info_length);
		es_pid = SI_MERGE_HL8(stream->elementary_pid);

		desc_loop_parser(stream->descriptor, es_info_length, ttx_desc_info, 1, NULL, (void *)&es_pid);

	}
	return SUCCESS;
}

INT32 ttx_unregister(UINT32 monitor_id)
{
	UINT16 stuff_pid = 0x1FFF;
	struct sim_cb_param param;
	if( (sim_get_monitor_param(monitor_id, &param) == SUCCESS) )
	{
		if( sim_unregister_scb(monitor_id, ttx_callback) != SUCCESS)
		{
			LIBTTX_PRINTF("ttx unreg to monitor fail. %d\n",monitor_id);
			return ERR_FAILUE;
		}
	}
	LIBTTX_PRINTF("ttx unreg to monitor. %d\n",monitor_id);

	if(ttx_is_holded()==FALSE)	
		ttx_descriptor(TELTEXT_DESCRIPTOR, 0, prev_ttext, (void *)&stuff_pid);
	return SUCCESS;
}


static UINT8 ttx_cur_monitor_id = 0xff;
INT32 ttx_register(UINT32 monitor_id)
{
	struct sim_cb_param param;
	if( sim_get_monitor_param(monitor_id, &param) != SUCCESS)
	{
		LIBTTX_PRINTF("ttx reg to monitor fail1. %d\n",monitor_id);
		return ERR_FAILUE;
	}
	
	ttx_unregister(ttx_cur_monitor_id);	
	
	if( sim_register_scb(monitor_id, ttx_callback, NULL) ==SUCCESS)
	{
		dmx_index = param.dmx_idx;
		LIBTTX_PRINTF("ttx reg to monitor succ. %d\n",monitor_id);
		ttx_cur_monitor_id = monitor_id;
		return SUCCESS;
	}
	
	LIBTTX_PRINTF("ttx reg to monitor fail2. %d\n",monitor_id);
	return ERR_FAILUE;	
}


#endif

static UINT8 ttx_dmx_used[3] = {0,0,0};
static RET_CODE ttx_unreg_all_dmx()
{
	static struct dmx_device *dmx_dev;
	RET_CODE reg_code = RET_SUCCESS;
	UINT8 i = 0;
	for(i=0; i<3; i++)
	{
		if(ttx_dmx_used[i])
		{
			dmx_dev = (struct dmx_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, i); 
			reg_code = dmx_unregister_service(dmx_dev,3);
			if(reg_code != RET_SUCCESS)
			{
				LIBTTX_PRINTF("ttx unregister dmx %d failed\n",i);
				return !RET_SUCCESS;
			}
			ttx_dmx_used[i]=0;
		}
	}
}

UINT32 g_ttx_desc_get = 0;

/*
ttx_descriptor : called by si_moniter to init ttx and refresh ttx info.
*/
INT32 ttx_descriptor(UINT8 tag, INT32 desc_length, UINT8 *desc, void *param)
{
	UINT8 lang_idx;
	UINT8 mag;
	UINT16 page=100;
	UINT8 teletext_type;
	struct register_service ttx_Serv ;
	struct dmx_device *dmx_dev = NULL;
    BOOL init_page_update = FALSE;
    BOOL subt_page_update = FALSE;
    struct ttx_page_info ttx_page_update;
    g_is_ttx_available = TRUE;
	UINT16 pid = *((UINT16*)param);

	if(g_ttx_pvr_enable == TRUE)
		goto _exit;
	
#ifdef LIB_TSI3_FULL
	if(desc_length>0 && desc_length<256 )
	{
		if(pid!=0x1FFF && MEMCMP(desc, prev_ttext, desc_length) == 0)
			goto _exit;

		MEMSET(prev_ttext, 0, sizeof(prev_ttext));
		MEMCPY(prev_ttext, desc, desc_length);
	}
	else if(desc_length==0)
	{
		if(pid>=0x20&&pid<0x1fff) //valid pid
		{
			for(lang_idx = 0;lang_idx<g_init_page_num;lang_idx++)
			{
				if(pid==g_init_page[lang_idx].pid)//check exist already
					goto _exit;
			}
		}
	}
#endif

	dmx_dev = (struct dmx_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, dmx_index);
	
	//libc_printf("desc_length=%d,pid=%d,g_init_page_num=%d\n",desc_length,pid,g_init_page_num);
	if(pid <0x20 || pid == 0x1fff)		
	{
		LIBTTX_PRINTF("%s: invalid pid 0x%X!!\n",__FUNCTION__,pid);
		g_current_pid = 0X1FFF;
		g_init_page_num = 0;
		g_subt_page_num = 0;		
		g_current_init_page = 0xff;
		g_current_subt_page = 0xff;
		g_is_ttx_available = FALSE;
#ifdef LIB_TSI3_FULL
		MEMSET(prev_ttext, 0, sizeof(prev_ttext));
#endif
		if(g_ttx_enable == TRUE)
		{
			if(RET_SUCCESS!=vbi_stop(ttx_dev))
			{
				LIBTTX_PRINTF("vbi_close failed!!\n");
				ASSERT(0);
			}
		}
		ttx_unreg_all_dmx();
		g_ttx_channel_enable = FALSE;		
		g_ttx_desc_get = 0;
        goto _exit;
	}
	if(g_ttx_enable == TRUE)
	{
		if(g_ttx_channel_enable == FALSE)
		{
			ttx_Serv.device = ttx_dev;
			ttx_Serv.request_write = (Request_write)vbi_request_write;
			ttx_Serv.update_write = (Update_write)vbi_update_write;
			ttx_Serv.service_pid = pid;
			if( dmx_register_service(dmx_dev,3,&ttx_Serv) == RET_SUCCESS)
			{
				ttx_dmx_used[dmx_index] = 1;
			}
			g_ttx_channel_enable = TRUE;
		}

    	if(RET_SUCCESS!=vbi_start(ttx_dev,TTXEng_UpdPage))
		{
			LIBTTX_PRINTF("vbi_open failed!!\n");
			ASSERT(0);
		}	 
	}
	//vbi_register_cb(ttx_dev,TTXEng_UpdPage);
	
	if(desc_length < 5)
	{
		teletext_type=0;
		if(g_init_page_num>=TTX_SUBT_LANG_NUM)
			goto _exit;
		for(lang_idx = 0;lang_idx<g_init_page_num;lang_idx++)
		{
			//if((desc[0] == g_init_page[lang_idx].lang[0]) 
			//	&&(desc[1] == g_init_page[lang_idx].lang[1]) 
			//	&&(desc[2] == g_init_page[lang_idx].lang[2])
			//	&&(pid == g_init_page[lang_idx].pid)
			//	&&(page == g_init_page[lang_idx].page))
			if(pid == g_init_page[lang_idx].pid)
				break;
		}
		if(lang_idx>=g_init_page_num)
		{				
			g_init_page[g_init_page_num].lang[0]='x';
			g_init_page[g_init_page_num].lang[1]='x';
			g_init_page[g_init_page_num].lang[2]='x';	
			g_subt_page[g_subt_page_num].ttx_type = teletext_type;
			g_init_page[g_init_page_num].pid = pid;
			g_init_page[g_init_page_num].page = page;
			g_init_page_num ++;
            init_page_update = TRUE;
		}
	}
	
	while(desc_length>=5)
	{
		
		mag = (desc[3]&0x07)?(desc[3]&0x07):8;
		page = (desc[4]>>4)*10 + (desc[4]&0x0f);
		page += (mag * 100);
		teletext_type = desc[3]>>3;
        //libc_printf("mag=%d,page=%d,teletext_type=%d,g_init_page_num=%d\n",mag,page,teletext_type,g_init_page_num);
		if(teletext_type == 1 || teletext_type == 3 || teletext_type == 0)//initial teletext page or additional information page
		{
			if(g_init_page_num>=TTX_SUBT_LANG_NUM)
			{
				goto _exit;
			}				
			
			for(lang_idx = 0;lang_idx<g_init_page_num;lang_idx++)
			{
				if((desc[0] == g_init_page[lang_idx].lang[0]) 
					&&(desc[1] == g_init_page[lang_idx].lang[1]) 
					&&(desc[2] == g_init_page[lang_idx].lang[2])
					&&(teletext_type == g_subt_page[lang_idx].ttx_type)
					&&(pid == g_init_page[lang_idx].pid)
					&&(page == g_init_page[lang_idx].page))
					break;
			}
			if(lang_idx>=g_init_page_num)
			{				
				g_init_page[g_init_page_num].lang[0]=desc[0];
				g_init_page[g_init_page_num].lang[1]=desc[1];
				g_init_page[g_init_page_num].lang[2]=desc[2];			
				g_subt_page[g_subt_page_num].ttx_type = teletext_type;
				g_init_page[g_init_page_num].pid = pid;
				g_init_page[g_init_page_num].page = page;
				g_init_page_num++;
                init_page_update = TRUE;
			}
		}
		else if(teletext_type == 2 || teletext_type == 5)//subtitle teletext page & subtitle teletext page for impaired people
		{
			if(g_subt_page_num>=TTX_SUBT_LANG_NUM||100==page)// Colin>> for BUG 42268 the special stream
			{
				goto _exit;
			}				
			for(lang_idx = 0;lang_idx<g_subt_page_num;lang_idx++)
			{
				if((desc[0] == g_subt_page[lang_idx].lang[0]) 
					&&(desc[1] == g_subt_page[lang_idx].lang[1]) 
					&&(desc[2] == g_subt_page[lang_idx].lang[2])
					&&(teletext_type == g_subt_page[lang_idx].ttx_type)
					&&(pid == g_subt_page[lang_idx].pid)
					&&(page == g_subt_page[lang_idx].page))
					break;
			}
			if(lang_idx>=g_subt_page_num)
			{				
				g_subt_page[g_subt_page_num].lang[0]=desc[0];
				g_subt_page[g_subt_page_num].lang[1]=desc[1];
				g_subt_page[g_subt_page_num].lang[2]=desc[2];		
				g_subt_page[g_subt_page_num].ttx_type = teletext_type;
				g_subt_page[g_subt_page_num].pid = pid;
				g_subt_page[g_subt_page_num].page = page;              
				g_subt_page_num++;
                subt_page_update = TRUE;
			}
            if(/*page==100 &&*/ g_init_page_num==0)//some special streams have teletext_type=2 but they have ttx (Rating_Ter_OK.trp) by cloud fix bug:181 ttx can not show because of error descriptor
            {
                g_init_page[g_init_page_num].lang[0]=desc[0];
			    g_init_page[g_init_page_num].lang[1]=desc[1];
			    g_init_page[g_init_page_num].lang[2]=desc[2];			
				g_subt_page[g_subt_page_num].ttx_type = teletext_type;
				g_init_page[g_init_page_num].pid = pid;
				g_init_page[g_init_page_num].page = page;
				g_init_page_num++; 

                if((g_subt_page_num == 1) && (g_subt_page[0].page == 100))
                    g_subt_page_num = 0;//it is a wrong header, cloud
                init_page_update = TRUE;
            }
		}
#if 0
		else if((desc[3]>>3) == 5)//subtitle teletext page for impaired people
		{
			if(g_subt_page_num>=TTX_SUBT_LANG_NUM)
				return SI_SUCCESS;		
			for(lang_idx = 0;lang_idx<g_subt_page_num;lang_idx++)
			{
				if((desc[0] == g_subt_page[lang_idx].lang[0]) 
					&&(desc[1] == g_subt_page[lang_idx].lang[1]) 
					&&(desc[2] == g_subt_page[lang_idx].lang[2])
					&&(pid == g_subt_page[lang_idx].pid)
					&&(mag*100+page == g_subt_page[lang_idx].page))
					break;
			}
			if(lang_idx>=g_subt_page_num)
			{				
				g_subt_page[g_subt_page_num].lang[0]=desc[0];
				g_subt_page[g_subt_page_num].lang[1]=desc[1];
				g_subt_page[g_subt_page_num].lang[2]=desc[2];		
				
				g_subt_page[g_subt_page_num].pid = pid;
				g_subt_page[g_subt_page_num].page = mag*100+page;
				g_subt_page_num++;
			}
		}	
#endif
		desc +=5;
		desc_length -= 5;
	}

_exit:
    if(init_page_update)
    {
        ttx_page_update.num = g_init_page_num;
        ttx_page_update.page_addr = (UINT32)g_init_page;
        vbi_ioctl(ttx_dev,IO_VBI_ENGINE_UPDATE_INIT_PAGE, (UINT32)&ttx_page_update);
    }
    if(subt_page_update)
    {
        ttx_page_update.num = g_subt_page_num;
        ttx_page_update.page_addr = (UINT32)g_subt_page;
        vbi_ioctl(ttx_dev,IO_VBI_ENGINE_UPDATE_SUBT_PAGE, (UINT32)&ttx_page_update);
    }
	g_ttx_desc_get = 1;	
	return SI_SUCCESS;
		
}
#ifdef PVR_DYNAMIC_PID_MONITOR_SUPPORT
INT32 rec_ttx_descriptor(UINT16 dmx_id,UINT8 prog_index,UINT8 tag, INT32 desc_length, UINT8 *desc, void *param)
{
	UINT8 lang_idx;
	UINT8 mag;
	UINT16 page=100;
	UINT8 teletext_type;
	struct register_service ttx_Serv ;

	UINT16 pid = *((UINT16*)param);
	
	//libc_printf("desc_length=%d,pid=%d,g_init_page_num=%d\n",desc_length,pid,g_init_page_num);
	if(pid <0x20 || pid == 0x1fff)		
	{
#if 0	
		LIBTTX_PRINTF("%s: invalid pid 0x%X!!\n",__FUNCTION__,pid);
		g_current_pid = 0X1FFF;
		g_init_page_num = 0;
		g_subt_page_num = 0;		
		g_current_init_page = 0xff;
		g_current_subt_page = 0xff;

		if(g_ttx_enable == TRUE)
		{
			if(RET_SUCCESS!=vbi_stop(ttx_dev))
			{
				LIBTTX_PRINTF("vbi_close failed!!\n");
				ASSERT(0);
			}
		}
		dmx_unregister_service(dmx_dev,3);		
		g_ttx_channel_enable = FALSE;
		return SI_SUCCESS;	
#endif		
	}
#if 0	
	if(g_ttx_enable == TRUE)
	{
		if(g_ttx_channel_enable == FALSE)
		{
			ttx_Serv.device = ttx_dev;
			ttx_Serv.request_write = (Request_write)vbi_request_write;
			ttx_Serv.update_write = (Update_write)vbi_update_write;
			ttx_Serv.service_pid = pid;
			dmx_register_service(dmx_dev,3,&ttx_Serv);	
#ifdef CC_USE_TSG_PLAYER
			dmx_register_service(dmx_dev2,3,&ttx_Serv);	
#endif
	}

    	if(RET_SUCCESS!=vbi_start(ttx_dev,TTXEng_UpdPage))
		{
			LIBTTX_PRINTF("vbi_open failed!!\n");
			ASSERT(0);
		}	 
	}
	//vbi_register_cb(ttx_dev,TTXEng_UpdPage);
#endif	
	if(desc_length < 5)
	{
		if(rec_monitor_id_g_init_page_num[dmx_id][prog_index]>=TTX_SUBT_LANG_NUM)
			return SI_SUCCESS;
		for(lang_idx = 0;lang_idx<rec_monitor_id_g_init_page_num[dmx_id][prog_index];lang_idx++)
		{
			if((desc[0] == rec_monitor_id_g_init_page[dmx_id][prog_index][lang_idx].lang[0]) 
				&&(desc[1] == rec_monitor_id_g_init_page[dmx_id][prog_index][lang_idx].lang[1]) 
				&&(desc[2] == rec_monitor_id_g_init_page[dmx_id][prog_index][lang_idx].lang[2])
				&&(pid == rec_monitor_id_g_init_page[dmx_id][prog_index][lang_idx].pid)
				&&(page == rec_monitor_id_g_init_page[dmx_id][prog_index][lang_idx].page))
				break;
		}
		if(lang_idx>=rec_monitor_id_g_init_page_num[dmx_id][prog_index])
		{				
			rec_monitor_id_g_init_page[dmx_id][prog_index][rec_monitor_id_g_init_page_num[dmx_id][prog_index]].lang[0]='x';
			rec_monitor_id_g_init_page[dmx_id][prog_index][rec_monitor_id_g_init_page_num[dmx_id][prog_index]].lang[1]='x';
			rec_monitor_id_g_init_page[dmx_id][prog_index][rec_monitor_id_g_init_page_num[dmx_id][prog_index]].lang[2]='x';		
			rec_monitor_id_g_init_page[dmx_id][prog_index][rec_monitor_id_g_init_page_num[dmx_id][prog_index]].pid = pid;
			rec_monitor_id_g_init_page[dmx_id][prog_index][rec_monitor_id_g_init_page_num[dmx_id][prog_index]].page = page;
			rec_monitor_id_g_init_page_num[dmx_id][prog_index] ++;
		}
	}

	while(desc_length>=5)
	{
		
		mag = (desc[3]&0x07)?(desc[3]&0x07):8;
		page = (desc[4]>>4)*10 + (desc[4]&0x0f);
		page += (mag * 100);
		teletext_type = desc[3]>>3;
        //libc_printf("mag=%d,page=%d,teletext_type=%d,g_init_page_num=%d\n",mag,page,teletext_type,g_init_page_num);
		if(teletext_type == 1 || teletext_type == 3)//initial teletext page or additional information page
		{
			if(rec_monitor_id_g_init_page_num[dmx_id][prog_index]>=TTX_SUBT_LANG_NUM)
				return SI_SUCCESS;
			
			for(lang_idx = 0;lang_idx<rec_monitor_id_g_init_page_num[dmx_id][prog_index];lang_idx++)
			{
				if((desc[0] == rec_monitor_id_g_init_page[dmx_id][prog_index][lang_idx].lang[0]) 
					&&(desc[1] == rec_monitor_id_g_init_page[dmx_id][prog_index][lang_idx].lang[1]) 
					&&(desc[2] == rec_monitor_id_g_init_page[dmx_id][prog_index][lang_idx].lang[2])
					&&(pid == rec_monitor_id_g_init_page[dmx_id][prog_index][lang_idx].pid)
					&&(page == rec_monitor_id_g_init_page[dmx_id][prog_index][lang_idx].page))
					break;
			}
			if(lang_idx>=rec_monitor_id_g_init_page_num[dmx_id][prog_index])
			{				
				rec_monitor_id_g_init_page[dmx_id][prog_index][rec_monitor_id_g_init_page_num[dmx_id][prog_index]].lang[0]=desc[0];
				rec_monitor_id_g_init_page[dmx_id][prog_index][rec_monitor_id_g_init_page_num[dmx_id][prog_index]].lang[1]=desc[1];
				rec_monitor_id_g_init_page[dmx_id][prog_index][rec_monitor_id_g_init_page_num[dmx_id][prog_index]].lang[2]=desc[2];			

				rec_monitor_id_g_init_page[dmx_id][prog_index][rec_monitor_id_g_init_page_num[dmx_id][prog_index]].pid = pid;
				rec_monitor_id_g_init_page[dmx_id][prog_index][rec_monitor_id_g_init_page_num[dmx_id][prog_index]].page = page;
				rec_monitor_id_g_init_page_num[dmx_id][prog_index]++;
			}
		}
		else if(teletext_type == 2 || teletext_type == 5)//subtitle teletext page & subtitle teletext page for impaired people
		{
			if(rec_monitor_id_g_subt_page_num[dmx_id][prog_index]>=TTX_SUBT_LANG_NUM)
				return SI_SUCCESS;	
			for(lang_idx = 0;lang_idx<rec_monitor_id_g_subt_page_num[dmx_id][prog_index];lang_idx++)
			{
				if((desc[0] == rec_monitor_id_g_subt_page[dmx_id][prog_index][lang_idx].lang[0]) 
					&&(desc[1] == rec_monitor_id_g_subt_page[dmx_id][prog_index][lang_idx].lang[1]) 
					&&(desc[2] == rec_monitor_id_g_subt_page[dmx_id][prog_index][lang_idx].lang[2])
					&&(pid == rec_monitor_id_g_subt_page[dmx_id][prog_index][lang_idx].pid)
					&&(page == rec_monitor_id_g_subt_page[dmx_id][prog_index][lang_idx].page))
					break;
			}
			if(lang_idx>=rec_monitor_id_g_subt_page_num[dmx_id][prog_index])
			{				
				rec_monitor_id_g_subt_page[dmx_id][prog_index][rec_monitor_id_g_subt_page_num[dmx_id][prog_index]].lang[0]=desc[0];
				rec_monitor_id_g_subt_page[dmx_id][prog_index][rec_monitor_id_g_subt_page_num[dmx_id][prog_index]].lang[1]=desc[1];
				rec_monitor_id_g_subt_page[dmx_id][prog_index][rec_monitor_id_g_subt_page_num[dmx_id][prog_index]].lang[2]=desc[2];		
				
				rec_monitor_id_g_subt_page[dmx_id][prog_index][rec_monitor_id_g_subt_page_num[dmx_id][prog_index]].pid = pid;
				rec_monitor_id_g_subt_page[dmx_id][prog_index][rec_monitor_id_g_subt_page_num[dmx_id][prog_index]].page = page;
				rec_monitor_id_g_subt_page_num[dmx_id][prog_index]++;
			}
            if(page==100 && rec_monitor_id_g_init_page_num[dmx_id][prog_index]==0)//some special streams have teletext_type=2 but they have ttx (Rating_Ter_OK.trp) by cloud
            {
                rec_monitor_id_g_init_page[dmx_id][prog_index][rec_monitor_id_g_init_page_num[dmx_id][prog_index]].lang[0]=desc[0];
			    rec_monitor_id_g_init_page[dmx_id][prog_index][rec_monitor_id_g_init_page_num[dmx_id][prog_index]].lang[1]=desc[1];
			    rec_monitor_id_g_init_page[dmx_id][prog_index][rec_monitor_id_g_init_page_num[dmx_id][prog_index]].lang[2]=desc[2];			

				rec_monitor_id_g_init_page[dmx_id][prog_index][rec_monitor_id_g_init_page_num[dmx_id][prog_index]].pid = pid;
				rec_monitor_id_g_init_page[dmx_id][prog_index][rec_monitor_id_g_init_page_num[dmx_id][prog_index]].page = page;
				rec_monitor_id_g_init_page_num[dmx_id][prog_index]++; 

                if((rec_monitor_id_g_subt_page_num[dmx_id][prog_index] == 1) && (rec_monitor_id_g_subt_page[dmx_id][prog_index][0].page == 100))
                    rec_monitor_id_g_subt_page_num[dmx_id][prog_index] = 0;//it is a wrong header, cloud
            }
		}
#if 0
		else if((desc[3]>>3) == 5)//subtitle teletext page for impaired people
		{
			if(g_subt_page_num>=TTX_SUBT_LANG_NUM)
				return SI_SUCCESS;		
			for(lang_idx = 0;lang_idx<g_subt_page_num;lang_idx++)
			{
				if((desc[0] == g_subt_page[lang_idx].lang[0]) 
					&&(desc[1] == g_subt_page[lang_idx].lang[1]) 
					&&(desc[2] == g_subt_page[lang_idx].lang[2])
					&&(pid == g_subt_page[lang_idx].pid)
					&&(mag*100+page == g_subt_page[lang_idx].page))
					break;
			}
			if(lang_idx>=g_subt_page_num)
			{				
				g_subt_page[g_subt_page_num].lang[0]=desc[0];
				g_subt_page[g_subt_page_num].lang[1]=desc[1];
				g_subt_page[g_subt_page_num].lang[2]=desc[2];		
				
				g_subt_page[g_subt_page_num].pid = pid;
				g_subt_page[g_subt_page_num].page = mag*100+page;
				g_subt_page_num++;
			}
		}	
#endif
		desc +=5;
		desc_length -= 5;
	}


	return SI_SUCCESS;
		
}
#endif
/*
TTXEng_GetSubtLang:
TTXEng_SetSubtLang:
	used in pairs
*/
UINT32 TTXEng_GetSubtLang(struct t_ttx_lang** list ,UINT8* num)
{
	*num = g_subt_page_num;
	*list = g_subt_page;	
	return g_ttx_desc_get;
}
#ifdef PVR_DYNAMIC_PID_MONITOR_SUPPORT
void Rec_Monitor_TTXEng_GetSubtLang(UINT16 dmx_id,UINT8 prog_index,struct t_ttx_lang** list ,UINT8* num)
{
	*num = rec_monitor_id_g_subt_page_num[dmx_id][prog_index];
	*list = rec_monitor_id_g_subt_page[dmx_id][prog_index];
	
}
#endif
UINT8 TTXEng_GetCurSubtLang(void)
{
	return g_current_subt_page;
}
INT32 TTXEng_SetSubtLang(UINT8 lang)
{
	UINT8 i;
	struct register_service ttx_Serv ;
	struct dmx_device *dmx_dev = NULL;

	if(lang>=g_subt_page_num)
		return ERR_FAILUE;

	g_current_subt_page = lang;
	//ttx_stop(ttx_dev);
	TTXEng_Close();
	dmx_dev = (struct dmx_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, dmx_index);
	if(g_subt_page[lang].pid != g_current_pid)
	{
		if (ttx_event_callback != NULL)
			ttx_event_callback(TTX_PID_UPDATE, g_subt_page[lang].pid);

		g_current_pid = g_subt_page[lang].pid;
		if(g_ttx_enable == TRUE || g_ttx_pvr_enable == TRUE)
		{
			ttx_unreg_all_dmx();
			ttx_Serv.device = ttx_dev;
			ttx_Serv.request_write = (Request_write)vbi_request_write;
			ttx_Serv.update_write = (Update_write)vbi_update_write;
			ttx_Serv.service_pid = g_current_pid;

			if( dmx_register_service(dmx_dev,3,&ttx_Serv) == RET_SUCCESS )
			{
				ttx_dmx_used[dmx_index] = 1;
			}
			g_ttx_channel_enable = TRUE;
		}
	}
	if(g_ttx_enable == TRUE || g_ttx_pvr_enable == TRUE)
	{

		if(RET_SUCCESS!=vbi_start(ttx_dev,TTXEng_UpdPage))
		{
			LIBTTX_PRINTF("vbi_open failed!!\n");
			ASSERT(0);
		}
	}

	g_current_language = g_subt_page[lang].lang;
    vbi_ioctl(ttx_dev,IO_VBI_ENGINE_SET_CUR_LANGUAGE, (UINT32)g_current_language);
	
	TTXEng_Open(TTXENG_SUBT,g_subt_page[lang].page);


	return SUCCESS;
}
/*
TTXEng_GetInitLang:
TTXEng_SetInitLang:
	used in pairs
*/
UINT32 TTXEng_GetInitLang(struct t_ttx_lang** list ,UINT8* num)
{
	*num = g_init_page_num;
	*list = g_init_page;
	return g_ttx_desc_get;	
}
#ifdef PVR_DYNAMIC_PID_MONITOR_SUPPORT

void Rec_Monitor_TTXEng_GetInitLang(UINT16 dmx_id,UINT8 index_id,struct t_ttx_lang** list ,UINT8* num)
{
	*num = rec_monitor_id_g_init_page_num[dmx_id][index_id];
	*list = rec_monitor_id_g_init_page[dmx_id][index_id];
}

#endif
INT32 TTXEng_SetInitLang(UINT8 lang)
{
	UINT8 i,ttx_status;
	struct register_service ttx_Serv ;
	struct dmx_device *dmx_dev = NULL;
    ttx_status = TTXENG_TEXT;

	if(lang>=g_init_page_num)
	{
        //libc_printf("lang>=g_init_page_num , lang=%d,g_init_page_num=%d,in TTXEng_SetInitLang\n", lang, g_init_page_num);
		//TTXEng_Close();
		return ERR_FAILUE;
	}

	g_current_init_page = lang;

	//ttx_stop(ttx_dev);
	TTXEng_Close();
	dmx_dev = (struct dmx_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, dmx_index);
	if(g_init_page[lang].pid != g_current_pid)
	{
		if (ttx_event_callback != NULL)
			ttx_event_callback(TTX_PID_UPDATE, g_init_page[lang].pid);

		g_current_pid = g_init_page[lang].pid;

		if(g_ttx_enable == TRUE || g_ttx_pvr_enable == TRUE)
		{
			ttx_unreg_all_dmx();
			ttx_Serv.device = ttx_dev;
			ttx_Serv.request_write = (Request_write)vbi_request_write;
			ttx_Serv.update_write = (Update_write)vbi_update_write;
			ttx_Serv.service_pid = g_current_pid;

			if( dmx_register_service(dmx_dev,3,&ttx_Serv) == RET_SUCCESS)
			{
				ttx_dmx_used[dmx_index] = 1;
			}
			g_ttx_channel_enable = TRUE;
		}
	}
	if(g_ttx_enable == TRUE || g_ttx_pvr_enable == TRUE)
	{

		if(RET_SUCCESS!=vbi_start(ttx_dev,TTXEng_UpdPage))
		{
			LIBTTX_PRINTF("vbi_open failed!!\n");
			ASSERT(0);
		}
	}

	g_current_language = g_init_page[lang].lang;
    vbi_ioctl(ttx_dev,IO_VBI_ENGINE_SET_CUR_LANGUAGE, (UINT32)g_current_language);

    if(get_inital_page()!=0xFF)
    {
        g_init_page_id = get_inital_page();//cloud
        ttx_status = get_inital_page_status();
    }
    else
    {
        g_init_page_id = 100;
    }
    //libc_printf("g_init_page_enable=%d,g_init_page_id=%d,g_init_page[lang].page=%d\n",g_init_page_enable,g_init_page_id,g_init_page[lang].page);
	if(TRUE == g_init_page_enable)
	{
        if(ttx_status == 1 && seperate_ttxsubtitle_mode == 1)
            TTXEng_Open(2,get_first_ttx_page());//cloud, for seperate ttx subtitle mode
        else
		    TTXEng_Open(ttx_status,g_init_page_id);
	}
	else
	    TTXEng_Open(ttx_status,g_init_page[lang].page);


	return SUCCESS;

}
void ttx_set_initpage(BOOL Enable, UINT16 page_id)
{
	g_init_page_enable = Enable;		
	if(page_id<100 || page_id>899)
		page_id = 100;	
	if(TRUE == Enable)
	{
		g_init_page_id = page_id;
	}	
}
void ttx_enable(BOOL Enable)
{
    LIBTTX_PRINTF("%s: Enable = %d\n", __FUNCTION__, Enable);
	struct register_service ttx_Serv ;
	struct dmx_device *dmx_dev = NULL;
    UINT8 ttx_eng_state;

    if(INVALID_ID == TTX_SEM_ID)
    {
	    TTX_SEM_ID = osal_semaphore_create(1);
	    if(INVALID_ID == TTX_SEM_ID)
	    {
		    PRINTF("INVALID_ID == TTX_SEM_ID!\n");
		    ASSERT(0);
	    }
    }

    if(ttx_dev == NULL)
    {
        if((ttx_dev = (struct vbi_device *)dev_get_by_type(NULL,HLD_DEV_TYPE_VBI))==NULL)
    	{
    		PRINTF("ttx_dev NOT exist!!\n");
    		ASSERT(0);
    	}
    }

	//dmx_dev = (struct dmx_device *)dev_get_by_type(NULL, HLD_DEV_TYPE_DMX);
	dmx_dev = (struct dmx_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, dmx_index);

    if(Enable)
    {
        vbi_ioctl(ttx_dev,IO_VBI_ENGINE_GET_STATE, (UINT32)(&ttx_eng_state));
		if((ttx_eng_state== TTXENG_TEXT && g_init_page_num>0 && g_current_pid != 0x1fff)
		||(ttx_eng_state== TTXENG_SUBT && g_subt_page_num>0 && g_current_pid != 0x1fff)			)
		{
			ttx_unreg_all_dmx();
			ttx_Serv.device = ttx_dev;
			ttx_Serv.request_write = (Request_write)vbi_request_write;
			ttx_Serv.update_write = (Update_write)vbi_update_write;
			ttx_Serv.service_pid = g_current_pid;
			if( dmx_register_service(dmx_dev,3,&ttx_Serv) == RET_SUCCESS)
			{
				ttx_dmx_used[dmx_index] = 1;
			}
			g_ttx_channel_enable = TRUE;
		}

		if(RET_SUCCESS!=vbi_start(ttx_dev,TTXEng_UpdPage))
		{
			LIBTTX_PRINTF("vbi_open failed!!\n");
			ASSERT(0);
		}
		g_ttx_enable = TRUE;
    }
    else
    {
	       ttx_unreg_all_dmx();
		if(RET_SUCCESS!=vbi_stop(ttx_dev))
		{
			LIBTTX_PRINTF("vbi_close failed!!\n");
			ASSERT(0);
		}
		g_current_pid = 0X1FFF;
		g_ttx_enable = FALSE;
    }
}


void TTXPvr_SetSubtLang(struct t_ttx_lang* list ,UINT8 num)
{
	UINT8 i = 0;
	int nSize = sizeof(struct t_ttx_lang);
    struct ttx_page_info ttx_page_update;
    
	g_subt_page_num = num;
	for(i=0; i<num; i++)
	{
		MEMCPY(&(g_subt_page[i]),&(list[i]),nSize);
	}
    ttx_page_update.num = g_subt_page_num;
    ttx_page_update.page_addr = (UINT32)g_subt_page;
    vbi_ioctl(ttx_dev,IO_VBI_ENGINE_UPDATE_SUBT_PAGE, (UINT32)&ttx_page_update);
}

void TTXPvr_SetInitLang(struct t_ttx_lang* list ,UINT8 num)
{
	UINT8 i = 0;
	int nSize = sizeof(struct t_ttx_lang);
    struct ttx_page_info ttx_page_update;
    
	g_init_page_num = num;
	for(i=0; i<num; i++)
	{
		MEMCPY(&(g_init_page[i]),&(list[i]),nSize);
	}
    ttx_page_update.num = g_init_page_num;
    ttx_page_update.page_addr = (UINT32)g_init_page;
    vbi_ioctl(ttx_dev,IO_VBI_ENGINE_UPDATE_INIT_PAGE, (UINT32)&ttx_page_update);
}


void ttx_pvr_enable(BOOL Enable,UINT16 dmx_id)
{
    LIBTTX_PRINTF("%s: Enable = %d\n", __FUNCTION__, Enable);
	struct register_service ttx_Serv ;
	struct dmx_device *dmx_dev = NULL;
    UINT8 ttx_eng_state;

	dmx_dev = (struct dmx_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, dmx_id);

	g_subt_page_num = 0;
	g_init_page_num = 0;

    if(Enable)
    {
    	dmx_index = dmx_id;
        vbi_ioctl(ttx_dev,IO_VBI_ENGINE_GET_STATE, (UINT32)(&ttx_eng_state));
		if((ttx_eng_state== TTXENG_TEXT && g_init_page_num>0 && g_current_pid != 0x1fff)
		||(ttx_eng_state== TTXENG_SUBT && g_subt_page_num>0 && g_current_pid != 0x1fff)			)
		{
			dmx_unregister_service(dmx_dev,3);
			ttx_Serv.device = ttx_dev;
			ttx_Serv.request_write = (Request_write)vbi_request_write;
			ttx_Serv.update_write = (Update_write)vbi_update_write;
			ttx_Serv.service_pid = g_current_pid;
			dmx_register_service(dmx_dev,3,&ttx_Serv);
			g_ttx_channel_enable = TRUE;
		}

		if(RET_SUCCESS!=vbi_start(ttx_dev,TTXEng_UpdPage))
		{
			LIBTTX_PRINTF("vbi_open failed!!\n");
			ASSERT(0);
		}
		g_ttx_pvr_enable = TRUE;
    }
    else
    {
    	if(g_ttx_pvr_enable)
			dmx_index = 0;
	       dmx_unregister_service(dmx_dev,3);
		if(RET_SUCCESS!=vbi_stop(ttx_dev))
		{
			LIBTTX_PRINTF("vbi_close failed!!\n");
			ASSERT(0);
		}
		g_current_pid = 0X1FFF;
		g_ttx_pvr_enable = FALSE;
#ifdef LIB_TSI3_FULL
		MEMSET(prev_ttext, 0, sizeof(prev_ttext));
		ttx_descriptor_reset();
#endif
		
    }
}

BOOL ttx_check_enable()
{
	return g_ttx_enable;
}

void ttx_reg_callback(TTX_EVENT_CALLBACK callback)
{
	osal_task_dispatch_off();
	ttx_event_callback = callback;
	osal_task_dispatch_on();
}

void ttx_unreg_callback()
{
	osal_task_dispatch_off();
	ttx_event_callback = NULL;
	osal_task_dispatch_on();
}
#endif

